package cymbol;

// define cymbol

import org.antlr.v4.runtime.ParserRuleContext;
import org.antlr.v4.runtime.Token;
import org.antlr.v4.runtime.tree.ParseTreeProperty;

public class DefPhase extends CymbolBaseListener {
    ParseTreeProperty<Scope> scopes = new ParseTreeProperty<Scope>();
    GlobalScope globals;
    // define symbols in this scope
    Scope currentScope;

    public void enterFile(CymbolParser.FileContext context) {
        globals = new GlobalScope(null);
        currentScope = globals;
    }

    public void exitFile(CymbolParser.FileContext context) {
        System.out.println(globals);
    }

    public void enterFunctionDecl(CymbolParser.FunctionDeclContext context) {
        String name = context.ID().getText();
        int typeTokenType = context.type().start.getType();
        Symbol.Type type = CheckSymbols.getType(typeTokenType);

        FunctionSymbol function = new FunctionSymbol(name, type, currentScope);
        // define function in current scope
        currentScope.define(function);
        // push: set function's parent to current
        saveScope(context, function);
        currentScope = function;
    }

    void saveScope(ParserRuleContext context, Scope s) {
        scopes.put(context, s);
    }

    public void exitFunctionDecl(CymbolParser.FunctionDeclContext context) {
        System.out.println(currentScope);
        currentScope = currentScope.getEnclosingScope();
    }

    public void enterBlock(CymbolParser.BlockContext context) {
        currentScope = new LocalScope(currentScope);
        saveScope(context, currentScope);
    }

    public void exitBlock(CymbolParser.BlockContext context) {
        System.out.println(currentScope);
        // pop scope
        currentScope = currentScope.getEnclosingScope();
    }

    public void exitFormalParameter(CymbolParser.FormalParameterContext context) {
        defineVar(context.type(), context.ID().getSymbol());
    }

    public void exitVarDecl(CymbolParser.VarDeclContext context) {
        defineVar(context.type(), context.ID().getSymbol());
    }

    void defineVar(CymbolParser.TypeContext typeContext, Token nameToken) {
        int typeTokenType = typeContext.start.getType();
        Symbol.Type type = CheckSymbols.getType(typeTokenType);
        VariableSymbol var = new VariableSymbol(nameToken.getText(), type);
        // define symbol in current scope
        currentScope.define(var);
    }
}
